package com.easywork.jythonspring;

import java.util.ArrayList;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.python.core.Py;
import org.python.core.PyFunction;
import org.python.core.PyObject;
import org.python.core.PyTableCode;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.support.WebContentGenerator;
/**
 * Python Handler Adaptor for handling Python controllers.
 * <p>
 * After mapping a python file to handle the request in {@link com.easywork.jythonspring.PythonHandlerMapping}, it'll return a
 * {@link org.python.core.PyFunction} object in the dispatcher. Then this adapter will be invoked to run the handle method for the user request.
 * </p>
 * <p>
 * The handle method should be define like this:
 * <pre><code>
 *  from org.springframework.web.servlet import ModelAndView
 * 	def home(req,resp,appCtx,myBean):
 * 	  appCtx.getBean("myBean")	#another method to get beans from context
 * 	  mv = ModelAndView("/home.vm")
 *    return mv
 *  </code></pre>
 * </p>
 * <p>
 * Where the method name is the same as the request URI name. The first parameter <i>self</i> contains an attribute <i>appCtx</i> which is the bean application
 * context in spring container. And the 2nd and 3rd arguments are the {@link javax.servlet.http.HttpServletRequest} and {@link javax.servlet.http.HttpServletResponse}
 * object. You can also pass the context bean from the handler method by adding parameter after response object and using the bean's name or id register in the spring
 * bean context as python method's argument name.
 * </p>
 * @author justicejiang
 *
 */
public class PythonHandlerAdapter extends WebContentGenerator implements HandlerAdapter {

	public long getLastModified(HttpServletRequest request, Object handler) {
		return -1;
	}

	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		ModelAndView mv = null;
		PyFunction pyHandler = (PyFunction) handler;
		//add spring bean context
		PyTableCode funcCode = (PyTableCode) pyHandler.func_code;
		//encapsulating python handler's parameters
		ArrayList<Object> params = new ArrayList<Object>();
		params.add(request);
		params.add(response);
		params.add(getApplicationContext());
		//extra parameters after the self, request and response
		if(funcCode.co_argcount > 3)
		{
			String beanName;
			for(int i = 3 ; i < funcCode.co_argcount;i++)
			{
				beanName = funcCode.co_varnames[i];
				Object param = null;
				if(getApplicationContext().containsBean(beanName))
				{
					//add this bean to context before invoking it
					param = getApplicationContext().getBean(beanName);
					params.add(param);
				}
			}
		}
		//call the handler method
		PyObject result = pyHandler._jcall(params.toArray());
		//convert the result into java object
		Object converted = result.__tojava__(ModelAndView.class);
		if(converted != Py.NoConversion)
			mv = (ModelAndView) converted;
		return mv;
	}

	public boolean supports(Object handler) {
		return handler instanceof PyObject;
	}

}
